/*  File Name	: GateService.cpp
 *  Author		: Javie Pong
 *	 E-mail		: 823960168@qq.com
 *  Created on	: 2012-7-1
 *  Description:
 */

#include "GateService.h"
#include "GateMonitor.h"

#ifdef DEBUG
#define SESSSION_TIMEOUT	60*10
#else
#define SESSSION_TIMEOUT	60*5	//session超时值（秒），超过该时间没有收到对方任何消息，则断开此连接
#endif

#define TIMER_VALUE			2		//定时器执行间隔(秒)
#define MAX_PACKET_IN_TIME	60		//如果在一个 TIMER_VALUE 时间内收到的数据包超过该值，则断开连接。防止数据包攻击

GateService::GateService(int p)
{
	this->reset();
}

GateService::~GateService()
{

}

void GateService::reset(void)
{
	this->role_id_ = 0;
	this->exception_ = false;
	this->is_engine_ = false;
	this->is_dircserver_ = false;
	this->is_dbsever_ = false;
	super::reset();
}

std::string GateService::name(void)
{
	return std::string("GateService");
}

const int GateService::role_id(void)
{
	return this->role_id_;
}

void GateService::role_id(int role_id)
{
	this->role_id_ = role_id;
}

bool GateService::is_engine(void)
{
	return this->is_engine_;
}

void GateService::set_engine(void)
{
	this->is_engine_= true;
}

bool GateService::is_dircserver(void)
{
	return this->is_dircserver_;
}

void GateService::set_dircsever(void)
{
	this->is_dircserver_ = true;
}

bool GateService::is_dbsever(void)
{
	return this->is_dbsever_;
}

void GateService::set_dbesver(void)
{
	this->is_dbsever_= true;
}

int GateService::open(void *p)
{
	if (this->monitor()->bind_service(this) < 0)
	{
		return -1;
	}

	if(super::open(this->reactor())!=0)
	{
		return -1;
	}

	//this->peer()->enable(O_NONBLOCK);
	//int buf_length = 1024*1024;
	//this->peer()->set_sockopt(SOL_SOCKET,SO_SNDBUF,&buf_length,sizeof(int));
	//this->peer()->set_sockopt(SOL_SOCKET,SO_RCVBUF,&buf_length,sizeof(int));

	if(this->start_timer(TimeValue(1),TimeValue(TIMER_VALUE))<0)
	{
		LOG((ERROR_LOG,"GateService::open-->start_timer error,[ip:%s][port:%d]",
				this->conn_addr_,this->port_));
		return -1;
	}

	LOG((DEBUG_LOG,"GateService::open-->[%s:%d]",this->conn_addr_,this->port_));

	return 0;
}

int GateService::handle_input(int fd)
{
	//LockGuardReturn(RT_MUTEX,rt_mutex,this->read_lock_,-1);

	super::handle_input(fd);
	if(INVALID_HANDLER != fd)
	{
		return this->recv_msg(1024);
	}
	return -1;
}

int GateService::handle_output(int fd)
{
	return 0;
}

int GateService::handle_timeout(void)
{
	if(this->is_engine() || this->is_dircserver())
	{
		return this->stop_timer();
	}

	int fd = this->peer()->get_handle();
	if(fd==INVALID_HANDLER)
	{
		LOG((DEBUG_LOG,"GateService::handle_timeout-->[fd:%d][%s:%d]",
						fd,this->conn_addr_,this->port_));
		this->stop_timer();
//		this->monitor()->unbind_service(this);
//		this->recycle(this);
		this->monitor()->handle_close(this);
		return -1;
	}

	if(TimeValue::now_time_in_sec()-this->last_recv_msg_>SESSSION_TIMEOUT)
	{
		LOG((DEBUG_LOG,"GateService::handle_timeout-->[fd:%d][%s:%d] session timeout",
				fd,this->conn_addr_,this->port_));
		this->reactor()->remove_handler(fd,this);
	}
	else if(this->recv_msg_count_ >=MAX_PACKET_IN_TIME)
	{
		LOG((ERROR_LOG,"GateService::handle_timeout-->[fd:%d][%s:%d][%d],too many packet",
				fd,this->conn_addr_,this->port_,this->recv_msg_count_));
		this->reactor()->remove_handler(fd,this);
	}
	this->recv_msg_count_ = 0;
	return 0;
}

int GateService::handle_close(int fd,ReactorMask mask)
{
	LOG((DEBUG_LOG,"GateService::handle_close-->[handle:%d][%s:%d]",
					fd,this->conn_addr_,this->port_));
	if(this->is_engine())
	{
		this->monitor()->unbind_room(this->role_id());
	}
	else if(this->is_dircserver())
	{
		this->monitor()->disconn_dircserver();
	}
	else if(this->is_dbsever())
	{
		this->monitor()->disconn_dbserver();
	}
	else
	{
		this->monitor()->log_out(this);
	}
	this->stop_timer();
	super::handle_close(fd,mask);
	//this->recycle(this);
	return this->monitor()->handle_close(this);
}

int GateService::is_flash_sanbox(MessageBlock *mb)
{
	//flash sandbox
	static const char szFlashSocketVerify[] = "<policy-file-request/>";
	static const char szFlashSocketVerifyReply[] =
			"<?xml version=\"1.0\"?><cross-domain-policy><allow-access-from domain=\"*\" to-ports=\"*\"/></cross-domain-policy>\0";

	if (mb->data_len() == sizeof(szFlashSocketVerify)
			&& 0== strncmp(szFlashSocketVerify,mb->rd_ptr(),
							sizeof(szFlashSocketVerify)))
	{
		mb->reset();
		mb->write(szFlashSocketVerifyReply,sizeof(szFlashSocketVerifyReply));
		this->send_msg(mb, mb->data_len());
		//this->monitor()->msg_pool()->pop(mb);
		return 0;
	}
	return -1;
}

int GateService::recv_msg(const int limit_size)
{
	MessageBlock *mb = NULL;
	if(this->monitor()->msg_pool()->pop(mb)!=0)
	{
		LOG((ERROR_LOG,"GateService::recv_msg-1->pop error"));
		return -1;
	}

	int len =0;
	bool has_data = false;
	do
	{
		mb->reset();
		len = super::recv_msg(mb, mb->size());
		if (len == -1 && (errno == EWOULDBLOCK || errno==EINTR))
		{
			this->monitor()->msg_pool()->push(mb);
			break;
		}
		else if (len <= 0)
		{
			LOG((DEBUG_LOG,"GateService::recv_msg-->recv:[%d],error:[%d:%s]",
					len,errno,strerror(errno)));
			this->monitor()->msg_pool()->push(mb);
			return -1;
		}
		has_data = true;
		if (is_flash_sanbox(mb)==0)
		{
			continue;
		}
		if (this->make_block(mb, len) == -1)
		{
			LOG((ERROR_LOG,"GateService::recv_msg-->make_block error"));
			return -1;
		}
	}while (len > 0);

	if(!has_data)
	{
		return 0;
	}

	int result = 0;
	do
	{
		MessageBlock *mb = NULL;
		if(this->monitor()->msg_pool()->pop(mb)!=0)
		{
			LOG((ERROR_LOG,"GateService::recv_msg-2->pop error"));
			return -1;
		}

		if(!this->is_engine())
		{
			*mb	<<this->unique_id() << this->role_id();
		}

		result = this->get_block(mb);
		if(result<0)
		{
			LOG((ERROR_LOG,"GateService::recv_msg-->get_block error[%d]",result));
			this->monitor()->msg_pool()->push(mb);
			return -1;
		}
		else if(result==0)
		{
			this->monitor()->msg_pool()->push(mb);
			return 0;
		}

		if(this->is_engine())
		{
			this->monitor()->respond_mb_push(mb);
		}
		else
		{
			this->monitor()->request_mb_push(mb);
		}
	}
	while(result==2);
	return 0;
}
